package com.cskaoyan.aspect;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

/**
 * @author stone
 * @date 2022/06/17 15:54
 */
@Aspect
@Component
public class CustomAspect {

    //@Pointcut注解增加在方法上 → value属性写切入点表达式，方法名作为切入点的id
    //<aop:pointcut id="servicePointcut" expression="execution(* com.cskaoyan.service..*(..))"/>
    @Pointcut("execution(* com.cskaoyan.service..*(..))")
    public void servicePointcut() {
    }

    // 切面组件中的方法，作为对应的通知方法 → 在对应的时间点下会执行到对应的方法
    // 通知注解的value属性：可以直接写切入点表达式；也可以引用切入点方法
    //@Before("execution(* com.cskaoyan.service..*(..))")
    @Before("servicePointcut()")
    public void beforex(JoinPoint joinPoint) {
        // 代理类
        Object proxy = joinPoint.getThis();
        // 目标类、委托类对象
        Object target = joinPoint.getTarget();
        // 参数
        Object[] args = joinPoint.getArgs();
        // 方法
        Signature signature = joinPoint.getSignature();
        String name = signature.getName();
        System.out.println("正在执行的方法：" + name);

        System.out.println("before方法");
    }

    @After("servicePointcut()")
    public void after() {
        System.out.println("after通知方法");
    }

    // Around通知 → 最强通知 ：返回值为Object，要有委托类方法的执行
    // 类似于InvocationHandler的invoke，类似于MethodInterceptor的invoke
    // 执行委托类的方法：ProceedingJoinPoint proceed方法
    @Around("servicePointcut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        long start = System.currentTimeMillis();
        System.out.println("开始时间：" + start);

        Object[] args = joinPoint.getArgs();
        String name = joinPoint.getSignature().getName();
        if ("add".equals(name)) {
            args[0] = (int)args[0] + 10;
            args[1] = (int)args[1] + 20;
        }

        //Object proceed = joinPoint.proceed(); // 执行委托类的方法
        // 如果想要使用处理后的参数作为委托类方法执行过程中的参数 → proceed(Object[])
        Object proceed = joinPoint.proceed(args); // 执行委托类的方法

        long end = System.currentTimeMillis();
        System.out.println("方法执行时间：" + (end - start));
        return proceed; // 就是作为代理对象执行方法的返回值
    }

    // afterReturning通知方法的形参，采用Object类型，接收委托类方法的返回值
    @AfterReturning(value = "servicePointcut()",returning = "result")
    public void afterReturning(Object result) {
        System.out.println("AfterReturning接收到的结果：" + result);
    }

    // public void afterThrowing(Exception exception) {
    @AfterThrowing(value = "servicePointcut()",throwing = "exception")
    public void afterThrowing(Throwable exception) {
        System.out.println("afterThrowing通知：" + exception.getMessage());
    }
}
